#ifndef __MOD_IPV4__
#define __MOD_IPV4__

#include "decoder.hpp"

// ========================================================================
class IPv4Session : public Session
{
private:
  u_int32_t LKey, RKey;

public:
  SessionRoot *root[3]; /* 0:TCP, 1:UDP, 2:ICMP */
  IPv4Session () : LKey (0), RKey (0) {
    this->root[0] = this->root[1] = this->root [2] = NULL;
  }  
  ~IPv4Session ()
  {    
    for (int i = 0; i < 3; i++)
      {
	if (this->root[i])
	  delete this->root [i];
      }
  }

  void setNode (Node * _LNode, Node * _RNode, u_int32_t &LKey, u_int32_t &RKey);
  Node * getNode (u_int32_t &key);
};

// ========================================================================
class IPv4Filter : public NDecFilter 
{
  friend class IPv4Decoder;

private:
  enum FilterType
    {
      FT_NULL = 0,
      FT_SRC_ADDR,
      FT_DST_ADDR,
    } type;
  u_int32_t addr, mask;
  void check (NDecResult &res);

public:
  IPv4Filter (FilterType t) : type (t), addr (0), mask (0) 
  {
    if (this->type == FT_SRC_ADDR || this->type == FT_DST_ADDR)
      this->setResultType (RT_ADDR);
  }
  ~IPv4Filter () {}

  bool setup (string &arg);
};

class IPv4MpxFilter : public NDecMpxFilter 
{
public:
  enum FilterType
    {
      FT_NULL = 0,
      FT_SRC_ADDR,
      FT_DST_ADDR,
    } ;

  IPv4MpxFilter (FilterType _type) : type (_type) {}
  ~IPv4MpxFilter () {}

  bool setup (string &name, void * p);
  int exec (NDecResult &res);

private:
  PTree<NDecMpxRes> ipTable;
  FilterType type;
};


// ========================================================================
class IPv4Record : public Record
{
  friend class IPv4Decoder;
  
private:
  u_int16_t totalLen;

public:
  IPv4Record () : totalLen (0) {}
  ~IPv4Record () {};
};

// ========================================================================
class IPv4Decoder : public Decoder
{
private:
  IPv4Record rec;
  Table<Node> * nodeTable;
  Table<Session> * ssnTable;
  static const int SSN_TIMEOUT = 60; // for DEBUG
  static const int ADDR_LEN = 4;

public:
  IPv4Decoder () 
  {
    this->nodeTable = new Hash<Node> (0x70000);
    this->ssnTable = new Hash<Session> (0x90000);
    // this->nodeTable = new PTree<Node> ();
    // this->ssnTable = new PTree<Session> ();
  }
  ~IPv4Decoder () 
  {
    delete this->ssnTable;
    delete this->nodeTable;
  }

  Record * decode (Packet & pkt, Record & prec);
  NDecFilter * makeFilter (string &name);
  NDecMpxFilter * makeMpxFilter (string &name);
  static void timeoutSession (void *);
};

#endif /* __MOD_IPV4__ */
